package edu.northwestern.cbits.purple_robot_manager.probes.services; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.support.v4.content.LocalBroadcastManager; import edu.northwestern.cbits.purple_robot_manager.R; import edu.northwestern.cbits.purple_robot_manager.WiFiHelper; import edu.northwestern.cbits.purple_robot_manager.activities.settings.FlexibleEditTextPreference; import edu.northwestern.cbits.purple_robot_manager.calibration.WeatherUndergroundCalibrationHelper; import edu.northwestern.cbits.purple_robot_manager.logging.LogManager; import edu.northwestern.cbits.purple_robot_manager.plugins.DataUploadPlugin; import edu.northwestern.cbits.purple_robot_manager.probes.Probe; import edu.northwestern.cbits.purple_robot_manager.probes.builtin.FusedLocationProbe; import edu.northwestern.cbits.purple_robot_manager.probes.builtin.LocationProbe; import edu.northwestern.cbits.purple_robot_manager.probes.builtin.RawLocationProbe; import edu.northwestern.cbits.purple_robot_manager.probes.features.Feature; public class WeatherUndergroundProbe extends Feature { private static final String FEATURE_KEY = "weather_underground"; protected static final String OBS_TIMESTAMP = "OBS_TIMESTAMP"; protected static final String WEATHER = "WEATHER"; protected static final String TEMPERATURE = "TEMPERATURE"; protected static final String WIND_DEGREES = "WIND_DEGREES"; protected static final String GUST_SPEED = "GUST_SPEED"; protected static final String PRESSURE_TREND = "PRESSURE_TREND"; protected static final String VISIBILITY = "VISIBILITY"; protected static final String WIND_SPEED = "WIND_SPEED"; protected static final String DEWPOINT = "DEWPOINT"; protected static final String WIND_DIR = "WIND_DIR"; protected static final String PRESSURE = "PRESSURE"; protected static final String STATION_ID = "STATION_ID"; protected static final String LOCATION = "LOCATION"; public static final String ENABLED = "config_feature_weather_underground_enabled"; public static final boolean DEFAULT_ENABLED = false; public static final String API_KEY = "config_last_weather_underground_api_key"; public static final String DEFAULT_API_KEY = ""; public static final String LAST_CHECK = "config_last_weather_underground_check"; private static final String PROBE_API_KEY = "api_key"; private boolean _isInited = false; private boolean _isEnabled = false; @Override public String getPreferenceKey() { return "services_weather_underground"; } @Override public String probeCategory(Context context) { return context.getString(R.string.probe_external_services_category); } @Override public String summarizeValue(Context context, Bundle bundle) { String weather = bundle.getString(WeatherUndergroundProbe.WEATHER); String station = bundle.getString(WeatherUndergroundProbe.STATION_ID); double temp = bundle.getDouble(WeatherUndergroundProbe.TEMPERATURE); return context.getResources().getString(R.string.summary_weather_underground_probe, weather, temp, station); } @Override protected String featureKey() { return WeatherUndergroundProbe.FEATURE_KEY; } @Override public String summary(Context context) { return context.getString(R.string.summary_weather_underground_feature_desc); } @Override public String name(Context context) { return "edu.northwestern.cbits.purple_robot_manager.probes.features.WeatherUndergroundFeature"; } @Override public String title(Context context) { return context.getString(R.string.title_weather_underground_feature); } @Override public void enable(Context context) { SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putBoolean(WeatherUndergroundProbe.ENABLED, true); e.commit(); } private long lastCheck(Context context) { SharedPreferences prefs = Probe.getPreferences(context); return prefs.getLong(WeatherUndergroundProbe.LAST_CHECK, 0); } @Override public void disable(Context context) { SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putBoolean(WeatherUndergroundProbe.ENABLED, false); e.commit(); } @Override public boolean isEnabled(Context context) { if (!this._isInited) { IntentFilter intentFilter = new IntentFilter(Probe.PROBE_READING); final WeatherUndergroundProbe me = this; BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, Intent intent) { Bundle extras = intent.getExtras(); String probeName = extras.getString(Probe.BUNDLE_PROBE); SharedPreferences prefs = Probe.getPreferences(context); final String apiKey = prefs.getString(WeatherUndergroundProbe.API_KEY, WeatherUndergroundProbe.DEFAULT_API_KEY); if (probeName != null && ((LocationProbe.NAME.equals(probeName)) || RawLocationProbe.NAME.equals(probeName) || FusedLocationProbe.NAME.equals(probeName)) && apiKey != null && apiKey.trim().length() > 0) { long now = System.currentTimeMillis(); if (now - me.lastCheck(context) > (1000 * 60 * 60)) { if (prefs.getBoolean(DataUploadPlugin.RESTRICT_TO_WIFI, true)) { if (WiFiHelper.wifiAvailable(context) == false) return; } Editor e = prefs.edit(); e.putLong(WeatherUndergroundProbe.LAST_CHECK, now); e.commit(); final double latitude = extras.getDouble(LocationProbe.LATITUDE); final double longitude = extras.getDouble(LocationProbe.LONGITUDE); Runnable r = new Runnable() { @Override public void run() { try { URL u = new URL("http://api.wunderground.com/api/" + apiKey + "/conditions/q/" + latitude + "," + longitude + ".json"); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); BufferedInputStream bin = new BufferedInputStream(conn.getInputStream()); ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int read = 0; while ((read = bin.read(buffer, 0, buffer.length)) != -1) { bout.write(buffer, 0, read); } bin.close(); String json = new String(bout.toByteArray(), "UTF-8"); JSONObject conditions = new JSONObject(json); JSONObject obs = conditions.getJSONObject("current_observation"); String location = obs.getJSONObject("observation_location").getString("full"); String stationId = obs.getString("station_id"); long obsTimestamp = Long.parseLong(obs.getString("observation_epoch")); String weather = obs.getString("weather"); double temp = Double.parseDouble(obs.getString("temp_c")); String windDir = obs.getString("wind_dir"); double windDegrees = obs.getDouble("wind_degrees"); double windSpeed = obs.getDouble("wind_kph"); double gustSpeed = obs.getDouble("wind_gust_kph"); double dewPoint = obs.getDouble("dewpoint_c"); double visiblility = obs.getDouble("visibility_km"); double pressure = Double.parseDouble(obs.getString("pressure_mb")); String pressureTrend = obs.getString("pressure_trend"); Bundle bundle = new Bundle(); bundle.putString(Probe.BUNDLE_PROBE, me.name(context)); bundle.putLong(Probe.BUNDLE_TIMESTAMP, System.currentTimeMillis() / 1000); bundle.putLong(WeatherUndergroundProbe.OBS_TIMESTAMP, obsTimestamp); bundle.putString(WeatherUndergroundProbe.STATION_ID, stationId); bundle.putString(WeatherUndergroundProbe.LOCATION, location); bundle.putString(WeatherUndergroundProbe.WEATHER, weather); bundle.putDouble(WeatherUndergroundProbe.TEMPERATURE, temp); bundle.putString(WeatherUndergroundProbe.WIND_DIR, windDir); bundle.putDouble(WeatherUndergroundProbe.WIND_DEGREES, windDegrees); bundle.putDouble(WeatherUndergroundProbe.WIND_SPEED, windSpeed); bundle.putDouble(WeatherUndergroundProbe.GUST_SPEED, gustSpeed); bundle.putString(WeatherUndergroundProbe.PRESSURE_TREND, pressureTrend); bundle.putDouble(WeatherUndergroundProbe.PRESSURE, pressure); bundle.putDouble(WeatherUndergroundProbe.DEWPOINT, dewPoint); bundle.putDouble(WeatherUndergroundProbe.VISIBILITY, visiblility); me.transmitData(context, bundle); } catch (Exception e) { LogManager.getInstance(context).logException(e); } } }; Thread t = new Thread(r); t.start(); } } } }; LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(context); localManager.registerReceiver(receiver, intentFilter); SharedPreferences prefs = Probe.getPreferences(context); prefs.edit().putLong(WeatherUndergroundProbe.LAST_CHECK, 0).commit(); this._isInited = true; } SharedPreferences prefs = Probe.getPreferences(context); this._isEnabled = false; if (super.isEnabled(context)) { if (prefs.getBoolean(WeatherUndergroundProbe.ENABLED, WeatherUndergroundProbe.DEFAULT_ENABLED)) this._isEnabled = true; } WeatherUndergroundCalibrationHelper.check(context, this._isEnabled); return this._isEnabled; } @Override public JSONObject fetchSettings(Context context) { JSONObject settings = super.fetchSettings(context); try { JSONObject apiKey = new JSONObject(); apiKey.put(Probe.PROBE_TYPE, Probe.PROBE_TYPE_STRING); settings.put(WeatherUndergroundProbe.PROBE_API_KEY, apiKey); } catch (JSONException e) { LogManager.getInstance(context).logException(e); } return settings; } public String assetPath(Context context) { return "current-weather-probe.html"; } @Override public Map<String, Object> configuration(Context context) { Map<String, Object> map = super.configuration(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); map.put(WeatherUndergroundProbe.PROBE_API_KEY, prefs.getString(WeatherUndergroundProbe.API_KEY, WeatherUndergroundProbe.DEFAULT_API_KEY)); return map; } @Override public void updateFromMap(Context context, Map<String, Object> params) { super.updateFromMap(context, params); if (params.containsKey(WeatherUndergroundProbe.PROBE_API_KEY)) { String value = params.get(WeatherUndergroundProbe.PROBE_API_KEY).toString(); SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putString(WeatherUndergroundProbe.API_KEY, value); e.commit(); } } @Override public PreferenceScreen preferenceScreen(final Context context, PreferenceManager manager) { PreferenceScreen screen = super.preferenceScreen(context, manager); screen.setTitle(this.title(context)); screen.setSummary(this.summary(context)); CheckBoxPreference enabled = new CheckBoxPreference(context); enabled.setTitle(R.string.title_enable_probe); enabled.setKey(WeatherUndergroundProbe.ENABLED); enabled.setDefaultValue(WeatherUndergroundProbe.DEFAULT_ENABLED); screen.addPreference(enabled); FlexibleEditTextPreference apiKey = new FlexibleEditTextPreference(context); apiKey.setKey(WeatherUndergroundProbe.API_KEY); apiKey.setTitle(R.string.config_weather_underground_api_key_title); apiKey.setDialogTitle(R.string.config_weather_underground_api_key_title); apiKey.setDialogMessage(R.string.config_weather_underground_api_key_message); screen.addPreference(apiKey); return screen; } }